package fr.ul.ade.prime.provider;

import java.util.List;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.DatabaseUtils.InsertHelper;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.provider.BaseColumns;
import fr.ul.ade.prime.database.CreateDatabases;
import fr.ul.ade.prime.database.DatabaseConstants;
import fr.ul.ade.prime.util.SelectionBuilder;

/**
 * @author Schnell Michaël, Zanette Sébastien
 * @version 1.2
 */
public class AdeWebProvider extends ContentProvider implements
		DatabaseConstants {

	protected static final String TAG = AdeWebProvider.class.getSimpleName();

	private CreateDatabases mOpenHelper;

	private static final UriMatcher sUriMatcher = buildUriMatcher();

	private static final int SCHEDULE = 100;
	private static final int SCHEDULE_ID = 101;

	private static final int LESSON = 200;
	private static final int LESSON_ID = 201;
	private static final int LESSON_SCHEDULE = 202;
	private static final int LESSON_SCHEDULE_BETWEEN = 203;

	private static final int PROJECT = 300;
	private static final int PROJECT_ID = 301;

	private static final int STUDENT_NUMBER = 400;
	private static final int STUDENT_NUMBER_ID = 401;

	private static UriMatcher buildUriMatcher() {
		final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
		final String authority = AdeWebContract.CONTENT_AUTHORITY;

		matcher.addURI(authority, AdeWebContract.PATH_SCHEDULE, SCHEDULE);
		matcher.addURI(authority,
				AdeWebContract.PATH_SCHEDULE + "/#", SCHEDULE_ID); //$NON-NLS-1$

		matcher.addURI(authority, AdeWebContract.PATH_LESSON, LESSON);
		matcher.addURI(authority, AdeWebContract.PATH_LESSON + "/#", LESSON_ID); //$NON-NLS-1$
		matcher.addURI(authority,
				AdeWebContract.PATH_LESSON + "/schedule/#", LESSON_SCHEDULE); //$NON-NLS-1$
		matcher.addURI(authority, AdeWebContract.PATH_LESSON
				+ "/schedule/between/*/*/#", LESSON_SCHEDULE_BETWEEN); //$NON-NLS-1$

		matcher.addURI(authority, AdeWebContract.PATH_PROJECT, PROJECT);
		matcher.addURI(authority,
				AdeWebContract.PATH_PROJECT + "/#", PROJECT_ID); //$NON-NLS-1$

		matcher.addURI(authority,
				AdeWebContract.PATH_STUDENT_NUMBER,
				STUDENT_NUMBER);
		matcher.addURI(authority,
				AdeWebContract.PATH_STUDENT_NUMBER + "/#", STUDENT_NUMBER_ID); //$NON-NLS-1$

		return matcher;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean onCreate() {
		this.mOpenHelper = new CreateDatabases(this.getContext());
		return true;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getType(Uri uri) {
		final int match = sUriMatcher.match(uri);
		switch (match) {
		case SCHEDULE:
			return AdeWebContract.Schedule.CONTENT_TYPE;
		case SCHEDULE_ID:
			return AdeWebContract.Schedule.CONTENT_ITEM_TYPE;
		case LESSON:
			return AdeWebContract.Lesson.CONTENT_TYPE;
		case LESSON_ID:
			return AdeWebContract.Lesson.CONTENT_ITEM_TYPE;
		case LESSON_SCHEDULE_BETWEEN:
			return AdeWebContract.Lesson.CONTENT_TYPE;
		case PROJECT:
			return AdeWebContract.Project.CONTENT_TYPE;
		case PROJECT_ID:
			return AdeWebContract.Project.CONTENT_ITEM_TYPE;
			// case STUDENT_NUMBER :
			// return AdeWebContract.StudentNumber.CONTENT_TYPE ;
			// case STUDENT_NUMBER_ID :
			// return AdeWebContract.StudentNumber.CONTENT_ITEM_TYPE ;
		default:
			throw new UnsupportedOperationException("Unknown uri: " + uri); //$NON-NLS-1$
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public synchronized Cursor query(Uri uri, String[] projection,
			String selection, String[] selectionArgs, String sortOrder) {
		final SQLiteDatabase db = this.mOpenHelper.getReadableDatabase();

		final int match = sUriMatcher.match(uri);
		switch (match) {
		default: {
			// Most cases are handled with simple SelectionBuilder
			final SelectionBuilder builder = buildSimpleSelection(uri);
			return builder.where(selection, selectionArgs).query(db,
					projection,
					sortOrder);
		}
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public synchronized Uri insert(Uri uri, ContentValues values) {
		final SQLiteDatabase db = this.mOpenHelper.getWritableDatabase();
		final int match = sUriMatcher.match(uri);
		Uri returnUri = null;
		switch (match) {
		case SCHEDULE: {
			long id = db.insertOrThrow(Tables.SCHEDULE_VIEW, null, values);
			returnUri = ContentUris.withAppendedId(uri, id);
			break;
		}
		case LESSON: {
			long id = db.insertOrThrow(Tables.LESSON, null, values);
			returnUri = ContentUris.withAppendedId(uri, id);
			break;
		}
		case PROJECT: {
			long id = db.insertOrThrow(Tables.PROJECT, null, values);
			returnUri = ContentUris.withAppendedId(uri, id);
			break;
		}
		// case STUDENT_NUMBER: {
		// long id = db.insertOrThrow(Tables.STUDENT_NUMBER, null, values) ;
		// getContext().getContentResolver().notifyChange(uri, null, false) ;
		// return ContentUris.withAppendedId(uri, id) ;
		// }
		default: {
			throw new UnsupportedOperationException("Unknown uri: " + uri); //$NON-NLS-1$
		}
		}// switch
		getContext().getContentResolver().notifyChange(returnUri, null, false);
		return returnUri;
	}

	@Override
	public int bulkInsert(Uri uri, ContentValues[] values) {
		final int match = sUriMatcher.match(uri);
		int nInserted = 0;
		switch (match) {
		case LESSON: {
			final SQLiteDatabase db = this.mOpenHelper.getWritableDatabase();
			final InsertHelper lessonInsert = new InsertHelper(db,
					Tables.LESSON_VIEW);
			for (ContentValues lessonValues : values) {
				long status = lessonInsert.insert(lessonValues);
				if (status != -1) {
					nInserted++;
				}// if
			}// for
			lessonInsert.close();
			break;
		}// case LESSON
		default: {
			return super.bulkInsert(uri, values);
		}// default
		}// switch
		return nInserted;
	}// bulkInsert(Uri, ContentValues[])

	/** {@inheritDoc} */
	@Override
	public synchronized int update(Uri uri, ContentValues values,
			String selection, String[] selectionArgs) {
		final SQLiteDatabase db = this.mOpenHelper.getWritableDatabase();
		final SelectionBuilder builder = buildSimpleSelection(uri);
		int retVal = builder.where(selection, selectionArgs).update(db, values);
		getContext().getContentResolver().notifyChange(uri, null, false);
		return retVal;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public synchronized int delete(Uri uri, String selection,
			String[] selectionArgs) {
		final SQLiteDatabase db = this.mOpenHelper.getWritableDatabase();
		final SelectionBuilder builder = buildSimpleSelection(uri);
		int retVal = builder.where(selection, selectionArgs).delete(db);
		getContext().getContentResolver().notifyChange(uri, null, false);
		return retVal;
	}

	/**
	 * Build a simple {@link SelectionBuilder} to match the requested
	 * {@link Uri}. This is usually enough to support {@link #insert},
	 * {@link #update}, and {@link #delete} operations.
	 */
	private static SelectionBuilder buildSimpleSelection(Uri uri) {
		final SelectionBuilder builder = new SelectionBuilder();
		final int match = sUriMatcher.match(uri);
		switch (match) {
		case SCHEDULE: {
			return builder.table(Tables.SCHEDULE_VIEW);
		}
		case SCHEDULE_ID: {
			final long scheduleId = ContentUris.parseId(uri);
			return builder.table(Tables.SCHEDULE_VIEW)
					.where(String.format("%s.%s = ?", //$NON-NLS-1$
							Tables.SCHEDULE_VIEW,
							BaseColumns._ID), Long.toString(scheduleId));
		}
		case LESSON: {
			return builder.table(Tables.LESSON_VIEW);
		}
		case LESSON_ID: {
			final long lessonId = ContentUris.parseId(uri);
			return builder.table(Tables.LESSON_VIEW)
					.where(AdeWebContract.Lesson._ID + "=" + lessonId); //$NON-NLS-1$
		}
		case LESSON_SCHEDULE: {
			final long scheduleId = ContentUris.parseId(uri);
			return builder.table(Tables.LESSON_VIEW)
					.where(AdeWebContract.Lesson.LESSON_SCHEDULE
							+ "=" + scheduleId); //$NON-NLS-1$
		}
		case LESSON_SCHEDULE_BETWEEN: {
			final List<String> segments = uri.getPathSegments();
			final String startDate = Uri.decode(segments.get(3));
			final String endDate = Uri.decode(segments.get(4));
			final long scheduleId = ContentUris.parseId(uri);
			return builder
					.table(Tables.LESSON_VIEW)
					.where(AdeWebContract.Lesson.LESSON_SCHEDULE
							+ "=" + scheduleId) //$NON-NLS-1$
					.where(String.format("(%1$s > '%3$s' AND %1$s <= '%4$s') OR (%1$s = '%3$s' AND %2$s >= strftime('%%H:%%M', 'now', 'localtime'))", //$NON-NLS-1$
							AdeWebContract.Lesson.LESSON_DATE,
							AdeWebContract.Lesson.LESSON_END_TIME,
							startDate,
							endDate));
		}
		case PROJECT: {
			return builder.table(Tables.PROJECT);
		}
		case PROJECT_ID: {
			final long projectId = ContentUris.parseId(uri);
			return builder.table(Tables.PROJECT)
					.where(AdeWebContract.Project._ID + "=" + projectId); //$NON-NLS-1$
		}
		case STUDENT_NUMBER: {
			return builder.table(Tables.STUDENT_NUMBER);
		}
		case STUDENT_NUMBER_ID: {
			final long studentNumber = ContentUris.parseId(uri);
			return builder.table(Tables.STUDENT_NUMBER)
					.where(AdeWebContract.StudentNumber._ID
							+ "=" + studentNumber); //$NON-NLS-1$
		}
		default: {
			throw new UnsupportedOperationException("Unknown uri: " + uri); //$NON-NLS-1$
		}
		}
	}

}
